package jmine.tec.hydra.export;

import java.util.ArrayList;
import java.util.List;

import jmine.tec.hydra.domain.enumx.HydraScriptPurposeIdentifier;
import jmine.tec.hydra.domain.filter.HydraFilterType;
import jmine.tec.hydra.services.incluir.FileSenderRegistryService;
import jmine.tec.hydra.services.incluir.HydraActivationService;
import jmine.tec.hydra.services.incluir.HydraFilterService;
import jmine.tec.hydra.services.incluir.HydraSpecificationService;
import jmine.tec.hydra.services.incluir.HydraSystemService;
import jmine.tec.hydra.services.incluir.MQSenderRegistryService;
import jmine.tec.hydra.services.incluir.ScriptSenderRegistryService;
import jmine.tec.script.impl.beanshell.BeanshellLanguageIdentifier;
import jmine.tec.script.impl.beanshell.BeanshellScriptExecutor;
import jmine.tec.script.persistent.dao.ScriptLanguageDAO;
import jmine.tec.script.persistent.dao.ScriptPurposeDAO;
import jmine.tec.script.persistent.dao.ScriptPurposeIdentifier;
import jmine.tec.script.persistent.domain.Script;
import jmine.tec.script.persistent.domain.ScriptLanguage;
import jmine.tec.script.persistent.domain.ScriptPurpose;
import jmine.tec.services.export.impl.ExportUtils;
import jmine.tec.services.io.ServiceBean;
import bancosys.tec.persist.controller.PersistenceEnabledController;
import bancosys.tec.persist.dao.BaseDAO;
import bancosys.tec.persist.dao.BeanNotFoundException;

/**
 * Factory de serviços que descrevem um sistema hydra que serve de exemplo para testes de exportação e empacotamento.
 * 
 * @author lundberg
 */
public class SampleHydraSystemServiceFactory {

    public static final long HYDRA_SYSTEM_0_ID = 42L;

    public static final long HYDRA_SYSTEM_1_ID = 53L;

    public static final long HYDRA_ACTIVATION_ID = 43L;

    public static final long HYDRA_FILTER_0_ID = 51L;

    public static final long HYDRA_FILTER_1_ID = 52L;

    public static final long HYDRA_SPECIFICATION_FILE_ID = 44L;

    public static final long HYDRA_SPECIFICATION_JMS_ID = 45L;

    public static final long HYDRA_SPECIFICATION_SCRIPT_ID = 46L;

    public static final long HYDRA_SPECIFICATION_EMPTY_ID = 53L;

    public static final long FILE_SENDER_REGISTRY_ID = 47L;

    public static final long JMS_SENDER_REGISTRY_ID = 48L;

    public static final long SCRIPT_SENDER_REGISTRY_ID = 49L;

    private PersistenceEnabledController controller;

    public SampleHydraSystemServiceFactory(PersistenceEnabledController controller) {
        this.controller = controller;
    }

    /**
     * @return
     */
    public List<ServiceBean> createSampleSystem() {
        List<ServiceBean> services = new ArrayList<ServiceBean>();

        ServiceBean system0 = new ServiceBean();
        ExportUtils.setService(system0, HydraSystemService.class);
        ExportUtils.put(system0, HydraSystemService.MNEMONICO, "SAMPLE_SYSTEM");
        ExportUtils.put(system0, HydraSystemService.ENCODING, "UTF-8");
        ExportUtils.put(system0, HydraSystemService.DATABASE_ID, HYDRA_SYSTEM_0_ID);
        ExportUtils.put(system0, HydraSystemService.IDENTIFICADOR, "$hydraSystem0");
        services.add(system0);

        ServiceBean activation = new ServiceBean();
        ExportUtils.setService(activation, HydraActivationService.class);
        ExportUtils.put(activation, HydraActivationService.MNEMONICO, "SAMPLE_ACTIVATION");
        ExportUtils.put(activation, HydraActivationService.SISTEMA, "$hydraSystem0");
        ExportUtils.put(activation, HydraActivationService.IDENTIFICADOR, "$hydraActivation0");
        ExportUtils.put(activation, HydraActivationService.DATABASE_ID, HYDRA_ACTIVATION_ID);
        ExportUtils.put(activation, HydraActivationService.SCRIPT, "SAMPLE_HYDRA_RECEIVE_ACTIVATION_SCRIPT");
        services.add(activation);

        ServiceBean filter0 = new ServiceBean();
        ExportUtils.setService(filter0, HydraFilterService.class);
        ExportUtils.put(filter0, HydraFilterService.MNEMONICO, "SAMPLE_FILTER_1");
        ExportUtils.put(filter0, HydraFilterService.SYSTEM, "$hydraSystem0");
        ExportUtils.put(filter0, HydraFilterService.IDENTIFICADOR, "$hydraFilter0");
        ExportUtils.put(filter0, HydraFilterService.DATABASE_ID, HYDRA_FILTER_0_ID);
        ExportUtils.put(filter0, HydraFilterService.SCRIPT, "SAMPLE_HYDRA_FILTERING_SCRIPT");
        ExportUtils.put(filter0, HydraFilterService.ACTION, "SAMPLE_ACTION");
        ExportUtils.put(filter0, HydraFilterService.FILTER_TYPE, HydraFilterType.RECEIVING);
        ExportUtils.put(filter0, HydraFilterService.ACTIVE, true);
        services.add(filter0);

        ServiceBean filter1 = new ServiceBean();
        ExportUtils.setService(filter1, HydraFilterService.class);
        ExportUtils.put(filter1, HydraFilterService.MNEMONICO, "SAMPLE_FILTER_2");
        ExportUtils.put(filter1, HydraFilterService.SYSTEM, "$hydraSystem0");
        ExportUtils.put(filter1, HydraFilterService.IDENTIFICADOR, "$hydraFilter1");
        ExportUtils.put(filter1, HydraFilterService.DATABASE_ID, HYDRA_FILTER_1_ID);
        ExportUtils.put(filter1, HydraFilterService.SCRIPT, "SAMPLE_HYDRA_FILTERING_SCRIPT");
        ExportUtils.put(filter1, HydraFilterService.FILTER_TYPE, HydraFilterType.SENDING);
        ExportUtils.put(filter1, HydraFilterService.ACTIVE, false);
        services.add(filter1);

        ServiceBean fileSender = new ServiceBean();
        ExportUtils.setService(fileSender, FileSenderRegistryService.class);
        ExportUtils.put(fileSender, FileSenderRegistryService.IDENTIFICADOR, "$fileSenderRegistry0");
        ExportUtils.put(fileSender, FileSenderRegistryService.MNEMONICO, "SAMPLE_FILE_SENDER_REGISTRY");
        ExportUtils.put(fileSender, FileSenderRegistryService.EXTENSION, ".xml");
        ExportUtils.put(fileSender, FileSenderRegistryService.PATH, "/tmp");
        ExportUtils.put(fileSender, FileSenderRegistryService.DATABASE_ID, FILE_SENDER_REGISTRY_ID);
        services.add(fileSender);

        ServiceBean specificationFile = new ServiceBean();
        ExportUtils.setService(specificationFile, HydraSpecificationService.class);
        ExportUtils.put(specificationFile, HydraSpecificationService.IDENTIFICADOR, "$hydraSpecification0");
        ExportUtils.put(specificationFile, HydraSpecificationService.ACTION, "SAMPLE_ACTION_FILE");
        ExportUtils.put(specificationFile, HydraSpecificationService.SYSTEM, "$hydraSystem0");
        ExportUtils.put(specificationFile, HydraSpecificationService.SENDER, "$fileSenderRegistry0");
        ExportUtils.put(specificationFile, HydraSpecificationService.ENCODE_SCRIPT, "SAMPLE_HYDRA_ENCODING_SCRIPT");
        ExportUtils.put(specificationFile, HydraSpecificationService.DECODE_SCRIPT, "SAMPLE_HYDRA_DECODING_SCRIPT");
        ExportUtils.put(specificationFile, HydraSpecificationService.TEMPLATE_SCRIPT, "SAMPLE_HYDRA_RENDERING_SCRIPT");
        ExportUtils.put(specificationFile, HydraSpecificationService.DATABASE_ID, HYDRA_SPECIFICATION_FILE_ID);
        services.add(specificationFile);

        ServiceBean jmsSender = new ServiceBean();
        ExportUtils.setService(jmsSender, MQSenderRegistryService.class);
        ExportUtils.put(jmsSender, MQSenderRegistryService.IDENTIFICADOR, "$jmsSenderRegistry0");
        ExportUtils.put(jmsSender, MQSenderRegistryService.MNEMONICO, "SAMPLE_JMS_SENDER_REGISTRY");
        ExportUtils.put(jmsSender, MQSenderRegistryService.QUEUE, "queue");
        ExportUtils.put(jmsSender, MQSenderRegistryService.QUEUE_CONNECTION_FACTORY, "queueConnectionFactory");
        ExportUtils.put(jmsSender, MQSenderRegistryService.DATABASE_ID, JMS_SENDER_REGISTRY_ID);
        services.add(jmsSender);

        ServiceBean specificationJMS = new ServiceBean();
        ExportUtils.setService(specificationJMS, HydraSpecificationService.class);
        ExportUtils.put(specificationJMS, HydraSpecificationService.IDENTIFICADOR, "$hydraSpecification1");
        ExportUtils.put(specificationJMS, HydraSpecificationService.ACTION, "SAMPLE_ACTION_JMS");
        ExportUtils.put(specificationJMS, HydraSpecificationService.SYSTEM, "$hydraSystem0");
        ExportUtils.put(specificationJMS, HydraSpecificationService.SENDER, "$jmsSenderRegistry0");
        ExportUtils.put(specificationJMS, HydraSpecificationService.ENCODE_SCRIPT, "SAMPLE_HYDRA_ENCODING_SCRIPT");
        ExportUtils.put(specificationJMS, HydraSpecificationService.DECODE_SCRIPT, "SAMPLE_HYDRA_DECODING_SCRIPT");
        ExportUtils.put(specificationJMS, HydraSpecificationService.TEMPLATE_SCRIPT, "SAMPLE_HYDRA_RENDERING_SCRIPT");
        ExportUtils.put(specificationJMS, HydraSpecificationService.DATABASE_ID, HYDRA_SPECIFICATION_JMS_ID);
        services.add(specificationJMS);

        ServiceBean scriptSender = new ServiceBean();
        ExportUtils.setService(scriptSender, ScriptSenderRegistryService.class);
        ExportUtils.put(scriptSender, ScriptSenderRegistryService.IDENTIFICADOR, "$scriptSenderRegistry0");
        ExportUtils.put(scriptSender, ScriptSenderRegistryService.MNEMONICO, "SAMPLE_SCRIPT_SENDER_REGISTRY");
        ExportUtils.put(scriptSender, ScriptSenderRegistryService.SCRIPT, "SAMPLE_HYDRA_SEND_ACTIVATION_SCRIPT");
        ExportUtils.put(scriptSender, ScriptSenderRegistryService.DATABASE_ID, SCRIPT_SENDER_REGISTRY_ID);
        services.add(scriptSender);

        ServiceBean specificationScript = new ServiceBean();
        ExportUtils.setService(specificationScript, HydraSpecificationService.class);
        ExportUtils.put(specificationScript, HydraSpecificationService.IDENTIFICADOR, "$hydraSpecification2");
        ExportUtils.put(specificationScript, HydraSpecificationService.ACTION, "SAMPLE_ACTION_SCRIPT");
        ExportUtils.put(specificationScript, HydraSpecificationService.SYSTEM, "$hydraSystem0");
        ExportUtils.put(specificationScript, HydraSpecificationService.SENDER, "$scriptSenderRegistry0");
        ExportUtils.put(specificationScript, HydraSpecificationService.ENCODE_SCRIPT, "SAMPLE_HYDRA_ENCODING_SCRIPT");
        ExportUtils.put(specificationScript, HydraSpecificationService.DECODE_SCRIPT, "SAMPLE_HYDRA_DECODING_SCRIPT");
        ExportUtils.put(specificationScript, HydraSpecificationService.TEMPLATE_SCRIPT, "SAMPLE_HYDRA_RENDERING_SCRIPT");
        ExportUtils.put(specificationScript, HydraSpecificationService.DATABASE_ID, HYDRA_SPECIFICATION_SCRIPT_ID);
        services.add(specificationScript);

        ServiceBean specificationEmpty = new ServiceBean();
        ExportUtils.setService(specificationEmpty, HydraSpecificationService.class);
        ExportUtils.put(specificationEmpty, HydraSpecificationService.IDENTIFICADOR, "$hydraSpecification3");
        ExportUtils.put(specificationEmpty, HydraSpecificationService.ACTION, "SAMPLE_ACTION_EMPTY");
        ExportUtils.put(specificationEmpty, HydraSpecificationService.SYSTEM, "$hydraSystem0");
        ExportUtils.put(specificationEmpty, HydraSpecificationService.DATABASE_ID, HYDRA_SPECIFICATION_EMPTY_ID);
        services.add(specificationEmpty);

        ServiceBean system1 = new ServiceBean();
        ExportUtils.setService(system1, HydraSystemService.class);
        ExportUtils.put(system1, HydraSystemService.MNEMONICO, "SAMPLE_SYSTEM_1");
        ExportUtils.put(system1, HydraSystemService.ENCODING, "UTF-8");
        ExportUtils.put(system1, HydraSystemService.DATABASE_ID, HYDRA_SYSTEM_1_ID);
        ExportUtils.put(system1, HydraSystemService.IDENTIFICADOR, "$hydraSystem1");
        services.add(system1);

        return services;
    }

    public void createSampleScripts() {
        this.createScript("SAMPLE_HYDRA_RECEIVE_ACTIVATION_SCRIPT", HydraScriptPurposeIdentifier.HYDRA_RECEIVE_ACTIVATION);
        this.createScript("SAMPLE_HYDRA_DECODING_SCRIPT", HydraScriptPurposeIdentifier.HYDRA_DECODING);
        this.createScript("SAMPLE_HYDRA_ENCODING_SCRIPT", HydraScriptPurposeIdentifier.HYDRA_ENCODING);
        this.createScript("SAMPLE_HYDRA_FILTERING_SCRIPT", HydraScriptPurposeIdentifier.HYDRA_FILTERING);
        this.createScript("SAMPLE_HYDRA_RENDERING_SCRIPT", HydraScriptPurposeIdentifier.HYDRA_RENDERING);
        this.createScript("SAMPLE_HYDRA_SEND_ACTIVATION_SCRIPT", HydraScriptPurposeIdentifier.HYDRA_SEND_ACTIVATION);
        this.createScript("SAMPLE_MESSAGE_DISPATCH_SCRIPT", HydraScriptPurposeIdentifier.MESSAGE_DISPATCH);
    }

    private void createScript(String mnemonico, ScriptPurposeIdentifier purpose) {
        BaseDAO<Script> scriptDAO = this.getController().getDAOFactory().getGenericDAO(Script.class);
        Script script = scriptDAO.createBean();
        script.setLanguage(this.findOrCreateBeanshell());
        script.setPurpose(this.findOrCreatePurpose(purpose));
        script.setMnemonico(mnemonico);
        script.setDescricao(mnemonico);
        this.createBody(script);
        script.getPersister().save();
    }

    /**
     * @param script script
     */
    private void createBody(Script script) {
        StringBuilder body = new StringBuilder();
        body.append("/**\n");
        body.append(" * Mnemônico: %s\n");
        body.append(" * Finalidade: %s\n");
        body.append(" */\nreturn null;");
        script.setBody(String.format(body.toString(), script.getMnemonico(), script.getPurpose().getMnemonico()));
    }

    /**
     * @param languageDAO
     * @return
     */
    @SuppressWarnings("deprecation")
    private ScriptLanguage findOrCreateBeanshell() {
        ScriptLanguageDAO dao = this.getController().getDAOFactory().getDAOByClass(ScriptLanguageDAO.class);
        try {
            return dao.findByPk(BeanshellLanguageIdentifier.BEANSHELL.getSystemId());
        } catch (BeanNotFoundException e) {
            ScriptLanguage language = dao.createBean();
            language.setAbreviacao("BSH");
            language.setMnemonico("BEANSHELL");
            language.setExecutorClass(BeanshellScriptExecutor.class.getCanonicalName());
            language.getController().getSessionFactory().getCurrentSession()
                    .save(language, BeanshellLanguageIdentifier.BEANSHELL.getSystemId());
            return language;
        }
    }

    /**
     * @param languageDAO
     * @return
     */
    @SuppressWarnings("deprecation")
    private ScriptPurpose findOrCreatePurpose(ScriptPurposeIdentifier identifier) {
        ScriptPurposeDAO dao = this.getController().getDAOFactory().getDAOByClass(ScriptPurposeDAO.class);
        try {
            return dao.findByPk(identifier.getSystemId());
        } catch (BeanNotFoundException e) {
            ScriptPurpose purpose = dao.createBean();
            purpose.setMnemonico(identifier.toString());
            purpose.getController().getSessionFactory().getCurrentSession().save(purpose, identifier.getSystemId());
            return purpose;
        }
    }

    public PersistenceEnabledController getController() {
        return this.controller;
    }
}
